home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
VideoToolbox 96.06.15
/
VideoToolboxSources
/
AtExitToShell.c
< prev
next >
Wrap
Text File
|
1996-06-11
|
6KB
|
136 lines
/*
AtExitToShell.c
void YourFunction(void);
error=AtExitToShell(YourFunction);
AtExitToShell(YourFunction) requests that your function be called when the
application quits, i.e. calls the ExitToShell trap, which tells the MacOS that
it's done. Your function must have no arguments and no return value.
(MATLAB: If you compile this file as a MEX resource, to be called from MATLAB,
then your call to AtExitToShell is a request that your function be called when
the MEX resource is flushed from memory.)
Many VideoToolbox routines set up interrupt service routines that must be killed
before the program goes away. We want to kill these whether we quit via exit(),
abort(), or the ExitToShell trap is invoked directly, e.g. if user types "ES"
in MacsBug. The only way to be sure of killing something before the application
goes away is to attach its killer, by patching, to the ExitToShell trap. That's
what's done here.
AtExitToShell() is closely modeled on the ANSI function atexit(). I wrote it to
overcome the restrictive implementation of atexit() and _atexit() in CodeWarrior:
they only invoke your functions if the ANSI function exit() is called, NOT if
you call abort(), or the user types "ES" in MacsBug. I think that AtExitToShell
is equivalent to the non-ANSI _atexit() routine provided by the Symantec THINK C
environment.
The registration list (of user functions) is last-in, first-out. When you
eventually quit, your functions will be called in reverse of the order in which
you registered them. No checking is made for duplication: the same function may
be registed multiple times, and will be called multiple times.
CAUTION: your application's runtime environment (e.g. stdio) will normally have
shut itself down by the time it calls ExitToShell(), so a function scheduled for
that time should not assume the availability of such services (e.g. printf).
There's no restriction on the use of MacOS services.
MATLAB: the Standard C atexit() and THINK C _atexit() routines should not be
used in MATLAB code resources, because they aren't designed to handle the
situation of code that may be flushed any time MATLAB executes "clear mex" or
"clear all", at a time unrelated to exiting of the MATLAB application itself.
Instead, MATLAB provides mexAtExit(), which allows you to register one callback
per MEX file, which is called when the MEX file is flushed. (The problem with using
mexAtExit, is that it's hard for any particular subroutine to know whether somebody
else has already used up the single available slot in the call-back table.)
In order to make your C subroutines as portable and autonomous as possible, you may
prefer to use this AtExitToShell() which allows you to register lots of callback
routines, and registers itself, once, with mexAtExit.
CAUTION: Since MATLAB registers only one function per MEX it is important that
you consistently adopt one strategy. Either make lots of calls to AtExitToShell
(and NONE to mexAtExit), or just one call to mexAtExit. If you call both AtExitToShell
and mexAtExit then one will displace the other in MATLAB's one-entry table.
The code to patch ExitToShell is based on examples that appeared in UseNet
csmp-digest-v3-046 by Kevin Bell (kbell@cs.utexas.edu) and Bill Hofmann
(wdh@netcom.com) in response to a query by Steve Coy (stevec@jolt.mpx.com.au)
HISTORY:
10/27/94 dgp wrote the ExitToShell patch, based on code from UseNet csmp-digest.
6/17/95 dgp wrote AtExitToShell.c
7/1/95 dgp made compatible with pre-universal apple headers.
Disable if MATLAB is true. Added comments about MATLAB.
7/17/95 dgp made compatible with pre-universal headers
4/19/96 dgp call mexAtExit(). I know this is ok for PPC, but may not work for 68k.
6/10/96 dgp fixed initialization error when MATLAB is true.
6/10/96 dgp added a couple paragraphs explaining its use in MATLAB MEX files.
6/11/96 dgp In response to concerns raised by David Brainard, I added text above
warning about the danger of calling BOTH AtExitToShell and mexAtExit, and
I made the A5 stuff conditional on !MATLAB.
*/
#include "VideoToolbox.h"
#ifndef __TRAPS__
#include <Traps.h> // _ExitToShell
#endif
#include <SegLoad.h> // ExitToShell()
#if UNIVERSAL_HEADERS
typedef UniversalProcPtr TrapAddressType;
#else
#define UniversalProcPtr ProcPtr
#define NewRoutineDescriptor(a,b,c) a
typedef long TrapAddressType;
#endif
static pascal void MyExitToShell(void);
#define FUNCTIONS 35
static UniversalProcPtr oldExitToShellTrapAddress=NULL; // save address of real ExitToShell trap.
static void (*userFunction[FUNCTIONS])(void); // table of user functions to be called at exit.
int AtExitToShell(void (*userFunctionPtr)(void))
{
#if !MATLAB
UniversalProcPtr myExitToShellUPP;
#endif
int i;
static Boolean firstTime=1;
if(firstTime){
#if !MATLAB
myExitToShellUPP=NewRoutineDescriptor((ProcPtr)MyExitToShell
,kPascalStackBased,GetCurrentISA());
oldExitToShellTrapAddress=(UniversalProcPtr)GetToolTrapAddress(_ExitToShell);
SetToolTrapAddress((TrapAddressType)myExitToShellUPP,_ExitToShell);
#else
// Ask MATLAB to call MyExitToShell just before disposing of our MEX resource.
mexAtExit((void *)MyExitToShell);
#endif
for(i=0;i<FUNCTIONS;i++)userFunction[i]=NULL;
firstTime=0;
}
for(i=0;i<FUNCTIONS;i++)if(userFunction[i]==NULL){
userFunction[i]=userFunctionPtr;
return 0; // success
}
return 1; // failure: the table's already full
}
static pascal void MyExitToShell(void)
{
int i;
#if !MATLAB
SetCurrentA5();
SetToolTrapAddress((TrapAddressType)oldExitToShellTrapAddress,_ExitToShell);
#endif
for(i=FUNCTIONS-1;i>=0;i--)if(userFunction[i]!=NULL){
(*userFunction[i])();
}
#if !MATLAB
ExitToShell();
#endif
}